package com.soyotec.algorithm.algorithm.process;

import com.soyotec.algorithm.context.OptAlgorithmContext;
import com.soyotec.algorithm.context.OptAlgorithmLogContext;
import com.soyotec.algorithm.util.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class AlgorithmRunner {
    final private Runtime runtime = Runtime.getRuntime();
    final private ExecutorService executorService = Executors.newFixedThreadPool(2);
    private Process process;
    private BufferedReader reader;
    private BufferedReader errorReader;
    private BufferedWriter writer;
    private final OptAlgorithmLogContext  logContext;
    private final OptAlgorithmContext  context;
    private  static Logger logger=  LoggerFactory.getLogger(AlgorithmRunner.class);
    public AlgorithmRunner (){
        logContext=null;
        context=null;

    }
    public AlgorithmRunner (OptAlgorithmContext  optAlgorithmContext){
        this.context=optAlgorithmContext;
        if(optAlgorithmContext!=null&&optAlgorithmContext instanceof OptAlgorithmLogContext){
            logContext=(OptAlgorithmLogContext)optAlgorithmContext;
        }else{
            logContext=null;
        }
    }


    protected Process createProcess(String[] command) throws IOException {

        File f=null;
        if(context.loadOtherFiles().length>0){
            f=context.loadOtherFiles()[0];
        }
        if(context!=null&&f!=null) {

            process = runtime.exec(command, null, f.getParentFile());
        }else{
            process = runtime.exec(command);
        }
        //将pid保存起来
        if (process != null && process.isAlive()) {
            String pid=  SystemUtils.getProcessId(process);
            System.out.println("pid= " + pid);
            Map<String, List<String>> pidMap = logContext.getPidMap();
            String instanceId = logContext.getInstanceId();
            List<String> pidList = pidMap.get(instanceId);
            if(pidList == null){
                //使用线程安全的list
                pidList = new CopyOnWriteArrayList<>();
            }
            pidList.add(pid);
            pidMap.put(instanceId,pidList);
        }
        return process;
    }

    protected Process createProcess(String[] command,File dir) throws IOException {

//        File f=null;
//        File[] otherFiles = context.loadOtherFiles();
//        if(otherFiles.length>0){
//            f=context.loadOtherFiles()[0];
//        }
//        if(context!=null&&f!=null) {
//
//            process = runtime.exec(command, null, f.getParentFile());
//        }else{
//            process = runtime.exec(command);
//        }
        process = runtime.exec(command, null, dir);
        //将pid保存起来
        if (process != null && process.isAlive()) {
            String pid=  SystemUtils.getProcessId(process);
            System.out.println("pid= " + pid);
            Map<String, List<String>> pidMap = logContext.getPidMap();
            String instanceId = logContext.getInstanceId();
            List<String> pidList = pidMap.get(instanceId);
            if(pidList == null){
                //使用线程安全的list
                pidList = new CopyOnWriteArrayList<>();
            }
            pidList.add(pid);
            pidMap.put(instanceId,pidList);
        }
        return process;
    }
    protected BufferedReader createReader(Process process){
        InputStreamReader inputStreamReader= null;
        try {
            inputStreamReader = new InputStreamReader(process.getInputStream(),"GB2312");
        } catch (UnsupportedEncodingException e) {
            logger.error("createReader失败：",e);
//            e.printStackTrace();
        }
        BufferedReader reader=new BufferedReader(inputStreamReader);
        return reader;
    }
    protected BufferedReader createErrorReader(Process process){
        InputStreamReader inputStreamReader= null;
        try {
            inputStreamReader = new InputStreamReader(process.getErrorStream(),"GB2312");
        } catch (UnsupportedEncodingException e) {
            logger.error("createErrorReader失败：",e);
//            e.printStackTrace();
        }
        BufferedReader reader=new BufferedReader(inputStreamReader);
        return reader;
    }
    protected   BufferedWriter createWriter(Process process){
        OutputStreamWriter outputStreamWriter= null;
        try {
            outputStreamWriter = new OutputStreamWriter(process.getOutputStream(),"GB2312");
        } catch (UnsupportedEncodingException e) {
            logger.error("createWriter失败：",e);
//            e.printStackTrace();
        }
        BufferedWriter writer=new BufferedWriter(outputStreamWriter);
        return  writer;
    }
    public int  runAlgorithm(String[] command,File dir,MessageHandler handler){


        try {
            Process process;
            if(dir==null) {
                process = createProcess(command);
            }else{
                process = createProcess(command, dir);
            }
//            System.out.println("==========create process end");
            reader=createReader( process);
//            System.out.println("==========create reader end");
            writer=createWriter( process);
//            System.out.println("==========create writer end");
            errorReader=createErrorReader(process);
//            System.out.println("==========create error reader end");


            executorService.execute(()->{
                try {
                    handler.handler(writer, reader, errorReader);
                }catch (Exception e){
                    destory();
                    System.out.println("--------------------------algorithm execption ----------------------e:"+e);
                    e.printStackTrace();
                    return ;
                }
            });
            executorService.execute(()->{

                String line="";
                try {

                    while ((line = errorReader.readLine()) != null) {
                        if(logContext!=null){
                            logContext.writeErrorLog(line,line);
                        }
                        logger.error(line);
                    }
                }catch (IOException e){
                    e.printStackTrace();
                    return ;
                }
            });
            return process.waitFor();
        } catch (Exception e) {
//            System.out.println("------------process-------Exception----------");
            e.printStackTrace();
        }finally {
           //destory();
        }
        return -1;//走到这里应该是出错了
    }

    public void writeInfoLog(String log){
        if(logContext != null){
            logContext.writeLog(log,log);
        }
    }

    public void destory() {
        if(process!=null) {
            SystemUtils.killProcessTree(process);
            System.out.println("------------process-------destory----------");
            if(process != null){
                process.destroy();
                process.destroyForcibly();
            }
            process=null;

//            System.out.println("------------process-------destory- end---------");
        }
        if(reader!=null) {
            try {
//                System.out.println("------------close-------reader----------");
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(errorReader!=null) {
            try {
//                System.out.println("------------close-------errorReader----------");
                errorReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(writer!=null) {
            try {
//                System.out.println("------------close-------writer----------");
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        executorService.shutdown();
    }

}
